// AStr.h

#pragma once
#ifndef ASTR_H_INCLUDED
#define ASTR_H_INCLUDED

#pragma warning(push)
#pragma warning(disable:4995)

#undef StrCat
#undef StrCmp
#undef StrCpy
#undef StrNCmp
#undef StrICmp
#undef StrNICmp

class AStr
{
	char*	m_sData;

public:
	~AStr();

	AStr();
	explicit AStr(const char cC);
	AStr(const AStr& sA);
	AStr(const char* sText);

	AStr& operator=(const AStr& sA);
	AStr& operator=(const char* sText);

	operator const char* () const;
	const char* c_str() const;

	char* GetInternalPointer() const {return m_sData;};
	void SetInternalPointer(char* p_sV) {m_sData=p_sV;};
	static void InternalAddRef(char* p_sV);
	static void InternalRelease(char* p_sV);

	void Isolate();
	char* GetBuffer(int p_iMinSize);

	char GetAt(int p_iIndex) const;
	void SetAt(int p_iIndex,char p_cChar);

	char operator[](int p_iAt) const {return GetAt(p_iAt);};

	int GetSize() const;

	int GetInternalCapacity() const;

	bool IsEqual(const AStr& p_sA) const;
	bool IsEqual(const char* p_sA) const;

	inline bool IsEmpty() const {return (GetSize()==0);};
	inline bool IsNotEmpty() const {return (GetSize()!=0);};
	void Clear();

	void Format(const char* p_sFormat,...);

	static AStr Create(const char* p_sFormat,...);
	static AStr CreateArgList(const char* p_sFormat,va_list& p_xL);
	static void BufferPrint(int p_iMaxSize,char* p_sBuffer,const char* p_sFormat,...);

	static int StrLen(const char* p_sS);
	static int StrCmp(const char* p_sS1,const char* p_sS2);
	static int StrICmp(const char* p_sS1,const char* p_sS2);
	static int StrNCmp(const char* p_sS1,const char* p_sS2,int p_iLen);
	static int StrNICmp(const char* p_sS1,const char* p_sS2,int p_iLen);
	static const char* StrChrFind(const char* p_sM,char p_cS);
	static const char* StrStrFind(const char* p_sM,const char* p_sS);
	static void StrNCopy(char* p_pkcDst,const char* p_sSrc,int p_iMax);
	static void StrCpy(char* p_pkcDst,const char* p_sSrc,int p_iMax=0);
	static void StrCat(char* p_pkcDst,const char* p_sSrc,int p_iMax=0);
	static void StrFormat(char* p_pkcDst,int p_iSize,const char* p_sFormat,...);

	static bool WildCardMatch(const char* p_sText,const char* p_sPattern);
	static bool WildCardMatch(const char* p_sText,const char* p_sPattern,DArray<AStr>& po_asMatches);
	static AStr WildCardRewrite(const char* p_sText,const char* p_sPattern,const char* p_sRewrite);

	AStr& operator+=(const AStr& p_sA);
	AStr& operator+=(const char* p_sA);
	AStr& operator+=(char p_cA);
	AStr operator+(const AStr& p_sA) const;
	AStr operator+(const char* p_sA) const;
	AStr operator+(char p_cA) const;

	int Compare(const AStr& p_sOp) const;
	int Compare(const char* p_sOp) const;
	int Compare(const char* p_sOp,int p_iMaxLen) const;
	int CompareMin(const char* p_sOp) const;
	int CompareNoCase(const char* p_sOp) const;
	int CompareNoCase(const char* p_sOp,int p_iMaxLen) const;
	int CompareNoCaseMin(const char* p_sOp) const;

	inline bool operator<(const AStr& p_sOp) const	{return Compare(p_sOp)<0;};
	inline bool operator<=(const AStr& p_sOp) const	{return Compare(p_sOp)<=0;};
	inline bool operator>(const AStr& p_sOp) const	{return Compare(p_sOp)>0;};
	inline bool operator>=(const AStr& p_sOp) const	{return Compare(p_sOp)>=0;};
	inline bool operator!=(const AStr& p_sOp) const	{return !IsEqual(p_sOp);};
	inline bool operator!=(const char* p_sOp) const	{return !IsEqual(p_sOp);};
	inline bool operator==(const AStr& p_sOp) const	{return IsEqual(p_sOp);};
	inline bool operator==(const char* p_sOp) const	{return IsEqual(p_sOp);};

	static bool IsLower(char p_cA);
	static bool IsUpper(char p_cA);
	static bool IsAlpha(char p_cA);
	static bool IsDigit(char p_cA);
	static bool IsAlphaNum(char p_cA);
	static bool IsWhitespace(char p_cA) {return (p_cA&0x7f)<=32;};

	static char ToLower(char p_cA);
	static char ToUpper(char p_cA);

	void MakeUpper();
	void MakeLower();
	AStr ToUpper() const;
	AStr ToLower() const;

	AStr Mid(int p_iStart) const;
	AStr Mid(int p_iStart,int p_iCount) const;
	AStr Left(int p_iCount) const;
	AStr Right(int p_iCount) const;

	void Cut(int p_iFirst,int p_iCount);

	static int CharFind(const char* p_sString,char p_cA);
	int Find(char p_cA) const;
	int Find(const char* p_sA) const;
	int Find(const char* p_sSub,int p_iStart) const;
	int Find(const AStr& p_sA) const;
	int Find(const AStr& p_sA,int p_iStart) const;
	int Find(char p_cA, int p_iStart) const;
	int FindOneOf(const char* p_sCharSet) const;
	int FindOneOf(const char* p_sCharSet,int p_iStart) const;
	int FindRev(char p_cA) const;
	int FindRev(const char* p_sA) const;
	int FindCStyle(char p_cA,int p_iStart=0) const;
	int FindCStyle(const char* p_sA,int p_iStart=0) const;

	void TrimLeft();
	void TrimLeft(char p_cTarget);
	void TrimLeft(const char* p_sTargets);

	void TrimRight();
	void TrimRight(char p_cTarget);
	void TrimRight(const char* p_sTargets);

	void Trim();
	void Trim(char p_cTarget);
	void Trim(const char* p_sTargets);

	void Fill(char p_cChar,int p_iCount);

	int Replace(char p_cOld, char p_cNew);
	int Replace(const char* p_sOld, const char* p_sNew);

	static AStr CStyleEncode(const AStr& p_sT,bool p_bEscapeSpaces=false,bool p_bConvertSpecialChars=true);
	static AStr CStyleDecode(const AStr& p_sT);
	static AStr HTMLEncode(const AStr& p_sT);

	void Split(DArray<AStr> &p_asTokens,const char* p_sSplitChars,bool p_bIgnoreEmptyTokens) const;
	void SplitCStyle(DArray<AStr> &p_asTokens,const char* p_sSplitChars,bool p_bIgnoreEmptyTokens) const;
	void SplitDelim(DArray<AStr> &p_asTokens,const char* p_sSplitChars) const;
	AStr Repeat(int p_iNum) const;

	static AStr Join(const DArray<AStr>& p_kasL,const char* p_pkcDelim=NULL,int p_iStartElem=0,int p_iEndElem=-1);

	uint32 HashVal() const
	{
		const char* sT=c_str();
		if(!sT){return 0;};
		uint32 iH=0xb791f3dd;
		while(*sT){iH+=((int)(*sT++))^((iH<<3)&0xffffffff)^((iH>>28)&0xffffffff);};
		return iH;
	};
};

#pragma warning(pop)

#endif
